package cn.jane.rpc.netty;

import cn.jane.rpc.api.RpcAccessPoint;
import cn.jane.rpc.api.spi.ServiceSupport;
import cn.jane.rpc.netty.client.StubFactory;
import cn.jane.rpc.netty.server.ServiceProviderRegistry;
import cn.jane.rpc.netty.transport.RequestHandlerRegistry;
import cn.jane.rpc.netty.transport.Transport;
import cn.jane.rpc.netty.transport.TransportClient;
import cn.jane.rpc.netty.transport.TransportServer;

import java.io.Closeable;
import java.net.InetSocketAddress;
import java.net.URI;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeoutException;

/**
 * 使用 Netty 实现的 {@link cn.jane.rpc.api.RpcAccessPoint}
 */
public class NettyRpcAccessPoint implements RpcAccessPoint {

    private static final String HOST = "127.0.0.1";
    private static final int PORT = 9999;
    private static final URI NAME_SERVICE_URI = URI.create(String.format("rpc://%s:%d", HOST, PORT));
    private static final Map<URI, Transport> CLIENT_MAP;
    private static final StubFactory STUB_FACTORY;
    private static final ServiceProviderRegistry SERVICE_PROVIDER_REGISTRY;

    private static TransportServer server;
    private static TransportClient client;

    static {
        CLIENT_MAP = new ConcurrentHashMap<>();
        STUB_FACTORY = ServiceSupport.load(StubFactory.class);
        SERVICE_PROVIDER_REGISTRY = ServiceSupport.load(ServiceProviderRegistry.class);

        server = null;
        client = ServiceSupport.load(TransportClient.class);
    }

    @Override
    public <T> T getRemoteService(URI serviceUri, Class<T> serviceClass) {
        Transport transport = CLIENT_MAP.computeIfAbsent(serviceUri, this::createTransport);
        return STUB_FACTORY.createStub(transport, serviceClass);
    }

    // 创建 Transport 对象并返回
    private Transport createTransport(URI uri) {
        try {
            return client.createTransport(new InetSocketAddress(uri.getHost(), uri.getPort()), 30000L);
        } catch (InterruptedException | TimeoutException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public <T> URI addServiceProvider(T service, Class<T> serviceClass) {
        SERVICE_PROVIDER_REGISTRY.addServiceProvider(service, serviceClass);
        return NAME_SERVICE_URI;
    }

    @Override
    public Closeable startServer() throws Exception {
        if (server == null) {
            server = ServiceSupport.load(TransportServer.class);
            server.start(RequestHandlerRegistry.getInstance(), PORT);
        }
        return () -> {
            if (server != null) {
                server.stop();
            }
        };
    }

    @Override
    public void close() {
        if (server != null) {
            server.stop();
        }
        client.close();
    }
}
